import {ethers} from "ethers";
import {randomSeed} from "../../libs/keyPair";
import {addTranToTranHistory, getChainBaseByChainID, getWalletInfo, nowWallet} from "./L2_Data";
import BigNumber from "bignumber.js";
import {BigMul, BigPow} from "./L2_utils";
import {Net} from "../../screens/axios";
import {Animated} from "react-native";

let provider: ethers.providers.JsonRpcProvider ;
const abi = [
    // Read-Only Functions
    "function balanceOf(address owner) view returns (uint256)",
    "function decimals() view returns (uint8)",
    "function symbol() view returns (string)",
    "function name() view returns (string)",
    // Authenticated Functions
    "function transfer(address to, uint256 amount) returns (bool)",
    // Events
    "event Transfer(address indexed from, address indexed to, uint amount)"
];
const initProvider = () => {
    // console.log(`initProvider`)
    // console.log(provider)

    provider = new ethers.providers.JsonRpcProvider(nowWallet.providerUrl);
    // provider = new ethers.providers.JsonRpcProvider('https://web3.mytokenpocket.vip');
    // provider = new ethers.providers.JsonRpcProvider('https://bsc-dataseed4.ninicoin.io');

}
export const getAddress = () => {
    console.log(nowWallet)
    return nowWallet.address;
}
export const getChainID = async (providerUrl: string) => {
    let providerTemp = new ethers.providers.JsonRpcProvider(providerUrl);
    let chainID = (await providerTemp.getNetwork()).chainId;
    return chainID
}

export const getGasPrice = async () => {
    initProvider();
    let gas = await provider.getGasPrice()
    let etherString = ethers.utils.formatEther(gas);
    return etherString;
}
export const getBalance = async (address:string) => {
    initProvider();
    let balance = await provider.getBalance(address)
    let etherString = ethers.utils.formatEther(balance);
    return etherString;
}
export const getBalanceWithProvider = async (address:string,providerUrl:string) => {
    let providerTemp = new ethers.providers.JsonRpcProvider(providerUrl);
    let balance = await providerTemp.getBalance(address)
    let etherString = ethers.utils.formatEther(balance);
    return etherString;
}
export const getTokenBalance = async (tokenAddress:string) => {
    initProvider();
    try{
        let walletInfo = await getWalletInfo(nowWallet.chainID, nowWallet.address)
        let wallet;
        if (walletInfo === null || walletInfo.privateKey === "") {
            return {success: false, falseReason: "请导入该钱包"}
        }
        wallet = getWalletByPrivateKeyWithProvider(walletInfo.privateKey)
        wallet.connect(provider)
        let contract = new ethers.Contract(tokenAddress,abi,provider);
        let balanceRes = await contract.balanceOf(nowWallet.address);
        let decimalsRes = await contract.decimals();
        let balance = new BigNumber(balanceRes._hex).div(new BigNumber(10).pow(decimalsRes)).toFixed();
        return {success:true,data:{balance}}
    }catch (e) {
        return {success:false,falseReason:e.message}
    }

}
export const getTokenDecimals = async (tokenAddress:string) => {
    initProvider();
    try{
        let walletInfo = await getWalletInfo(nowWallet.chainID, nowWallet.address)
        let wallet;
        if (walletInfo === null || walletInfo.privateKey === "") {
            return {success: false, falseReason: "请导入该钱包"}
        }
        wallet = getWalletByPrivateKeyWithProvider(walletInfo.privateKey)
        wallet.connect(provider)
        let contract = new ethers.Contract(tokenAddress,abi,provider);
        let decimals = await contract.decimals();
        return {success:true,data:{decimals}}
    }catch (e) {
        return {success:false,falseReason:e.message}
    }

}
export const getTokenSymbol = async (tokenAddress:string) => {
    initProvider();
    try{
        let walletInfo = await getWalletInfo(nowWallet.chainID, nowWallet.address)
        let wallet;
        if (walletInfo === null || walletInfo.privateKey === "") {
            return {success: false, falseReason: "请导入该钱包"}
        }
        wallet = getWalletByPrivateKeyWithProvider(walletInfo.privateKey)
        wallet.connect(provider)
        let contract = new ethers.Contract(tokenAddress,abi,provider);
        let symbol = await contract.symbol();
        return {success:true,data:{symbol}}
    }catch (e) {
        return {success:false,falseReason:e.message}
    }

}
export const getTokenName = async (tokenAddress:string) => {
    initProvider();
    try{
        let walletInfo = await getWalletInfo(nowWallet.chainID, nowWallet.address)
        let wallet;
        if (walletInfo === null || walletInfo.privateKey === "") {
            return {success: false, falseReason: "请导入该钱包"}
        }
        wallet = getWalletByPrivateKeyWithProvider(walletInfo.privateKey)
        wallet.connect(provider)
        let contract = new ethers.Contract(tokenAddress,abi,provider);
        let name = await contract.name();
        return {success:true,data:{name}}
    }catch (e) {
        return {success:false,falseReason:e.message}
    }

}
export const getTransferCount = async (address:string) => {
    initProvider();
    let transferCount = await provider.getTransactionCount(address)
    return transferCount;
}
export const getBlockNumber = async () => {
    initProvider();
    let blockNumber = await provider.getBlockNumber()
    return blockNumber;
}
export const getHeightByProviderUrl = async (providerUrl:string) => {
    try {
        let providerTemp = new ethers.providers.JsonRpcProvider(providerUrl);
        return await providerTemp.getBlockNumber()
    }catch (e) {
        return "0"
    }
}
export const getBlock = async (hash:string) => {
    initProvider();
    let block = await provider.getBlock(hash)
    return block;
}
export const getTransaction = async (hash:string) => {
    initProvider();
    let transaction = await provider.getTransaction(hash)
    return transaction;
}
export const getTransactionReceipt = async (hash:string) => {
    initProvider();
    let transactionReceipt = await provider.getTransactionReceipt(hash)
    return transactionReceipt;
}
//创建新钱包通过随机助记词
export const createNewMnemonic = () => {
    let newMnemonic = ethers.utils.entropyToMnemonic(ethers.utils.randomBytes(16));
    // let randomseed = randomSeed();
    // console.log(randomseed)
    // let zjc ="0x"+randomseed.slice(0,32);
    // console.log(zjc)
    // var mnemonic = ethers.utils.entropyToMnemonic(zjc);
    // // let path = "m/44'/60'/0'/0/0";
    // let wallet = ethers.Wallet.fromMnemonic(mnemonic);
    // console.log(wallet.address)
    console.log(newMnemonic)
    // console.log(wallet._signingKey())
    // console.log(wallet.privateKey)
    return newMnemonic;

}
//获取钱包通过Keystore和密码
export const getWalletByKeystore = async (KeystoreStr: string, password: string) => {
    try {
        let wallet = await ethers.Wallet.fromEncryptedJson(KeystoreStr, password);
        if (wallet) {
            return wallet;
        }
        return null;
    }catch (e) {
        return null;
    }
}
//获取钱包通过助记词
export const getWalletByMnemonic = (mnemonic:string) => {
    let wallet = ethers.Wallet.fromMnemonic(mnemonic);
    return wallet
}
//获取钱包通过私钥
export const getWalletByPrivateKey = (key:string) => {
    if(key.indexOf("0x")!==0)
    {
        key = "0x"+key;
    }
    let wallet = new ethers.Wallet(key);
    console.log(`getAddressByPrivateKey---wallet`)
    console.log(wallet)
    return wallet;
}
//获取地址keystore
export const getKeyStore = async (key:string,password:string) => {
    try {
        // 回调函数可以获取导出进度
        function callback(percent: any) {
            console.log("Encrypting: " + parseInt((percent * 100).toString()) + "% complete");
        }

        let wallet = new ethers.Wallet(key);
        let json = await wallet.encrypt(password, callback);
        console.log(json)
        return json;
    }catch (e) {
        console.log(`getKeyStoreError:${e}`)
        return "";
    }
}
//获取地址助记词
export const getWalletMnemonic = async (chainID: string, address: string) => {
    let walletInfo = await getWalletInfo(chainID,address);
    if(!walletInfo)
    {
        return null
    }
    return walletInfo.mnemonic.split(" ");

}
export const getWalletByPrivateKeyWithProvider = (key:string) => {
    if(key.indexOf("0x")!==0)
    {
        key = "0x"+key;
    }
    initProvider();
    let wallet = new ethers.Wallet(key,provider);
    return wallet;
}
export const getGasLimit = async (sendInfo:object) => {
    try {
        let walletInfo = await getWalletInfo(nowWallet.chainID, nowWallet.address)
        let wallet;
        if (walletInfo === null || walletInfo.privateKey === "") {
            return {success: false, falseReason: "请导入该钱包"}
        }
        wallet = getWalletByPrivateKeyWithProvider(walletInfo.privateKey)
        let gasLimitInfo: ethers.BigNumber = await wallet.estimateGas(sendInfo)
        return {success: true, data: gasLimitInfo};
    }
    catch (e) {
        return {success:false,falseReason:"获取gas失败"}
    }
}
export const getTokenGasLimit = async (tokenAddress:string,toAddress:string,amount:string) => {
    if(!tokenAddress || !toAddress || !amount)
    {
        return {success:false,falseReason:"请输入正确的地址和数量"};
    }
    initProvider();
    try{
        let walletInfo = await getWalletInfo(nowWallet.chainID, nowWallet.address)
        let wallet;
        if (walletInfo === null || walletInfo.privateKey === "") {
            return {success: false, falseReason: "请导入该钱包"}
        }
        wallet = getWalletByPrivateKeyWithProvider(walletInfo.privateKey)
        let contract = new ethers.Contract(tokenAddress,abi,wallet);
        let decimals = await contract.decimals();
        let amountTran = BigMul(amount,BigPow(10,decimals));
        let GasLimit = await contract.estimateGas.transfer(toAddress,new BigNumber(amountTran).toFixed());
        return {success:true,data:{GasLimit}}
    }catch (e) {
        console.log(e)
        return {success:false,falseReason:e.message}
    }
}
export const sendEth = async (sendInfo:object) => {
    try {
        let walletInfo = await getWalletInfo(nowWallet.chainID, nowWallet.address)
        let wallet;
        if (walletInfo === null || walletInfo.privateKey === "") {
            return {success: false, falseReason: "请导入该钱包"}
        }
        wallet = getWalletByPrivateKeyWithProvider(walletInfo.privateKey)
        let res = await wallet.sendTransaction(sendInfo);
        setTimeout(async ()=>{
            console.log(`addTranToTranHistoryResBefore`,res)
            let hash = res.data.hash;
            let resTemp = await addTranToTranHistory(false,hash,nowWallet.chainID,nowWallet.address,sendInfo.to,new Date().getTime().toString())
            console.log(`addTranToTranHistoryRes`,resTemp)
        },100)
        return {success: true, data:{res}};
    }
    catch (e) {
        return {success: false, falseReason: e.message}
    }
}
export const sendToken = async (tokenAddress:string,toAddress:string,amount:string,gasLimit:string,gasPriceGwei:string) => {
    initProvider();
    let gesLimitTemp = await getTokenGasLimit(tokenAddress,toAddress,amount)
    if(gesLimitTemp.success)
    {
        let gaslimitTempRes = gesLimitTemp.data.GasLimit;
        if(new BigNumber(ethers.utils.parseUnits(gaslimitTempRes.toString(), "wei").toString()).isGreaterThan(gasLimit) )
        {
            return {success:false,falseReason:`gasLimit 不得少于${ethers.utils.parseUnits(gaslimitTempRes.toString(), "wei").toString()}`}
        }
        try{
            let walletInfo = await getWalletInfo(nowWallet.chainID, nowWallet.address)
            let wallet;
            if (walletInfo === null || walletInfo.privateKey === "") {
                return {success: false, falseReason: "请导入该钱包"}
            }
            wallet = getWalletByPrivateKeyWithProvider(walletInfo.privateKey)
            let contract = new ethers.Contract(tokenAddress,abi,wallet);
            let decimals = await contract.decimals();
            let amountTran = BigMul(amount,BigPow(10,decimals));
            let tranTokenRes = await contract.transfer(toAddress,amountTran,{
                gasLimit: ethers.utils.parseUnits(gasLimit, "wei"),
                gasPrice: ethers.utils.parseUnits(gasPriceGwei, "gwei"),
            });
            console.log(`tranTokenRes`,tranTokenRes)
            return {success:true,data: {tranTokenRes}}
        }catch (e) {
            console.log(`sendToken:${e.message}`)
            return {success:false,falseReason:e.message}
        }

    }
    else
    {
        return gesLimitTemp
    }
}
export const sendTransfer_ETH = async (receiver:string,amount_ETH:string,gasPriceGwei:string,gasLimit:string,data:string) => {
    try {
        let sendInfo = {
            gasPrice: ethers.utils.parseUnits(gasPriceGwei, "gwei"),
            to: receiver,
            value: ethers.utils.parseEther(amount_ETH),
            data: data
        }
        console.log(sendInfo)
        let gasLimitInfo = await getGasLimit(sendInfo);
        if (!gasLimitInfo.success) {
            return {success: false, falseReason: gasLimitInfo.falseReason};
        }
        if (gasLimitInfo.data?.gt(ethers.utils.parseUnits(gasLimit, "wei"))) {
            let falseReason = `gasLimit必须不小于${gasLimitInfo.data.toString()}`;
            console.log(falseReason)
            return {success: false, falseReason}
        }
        sendInfo.gasLimit = ethers.utils.parseUnits(gasLimit, "wei")._hex;
        let res = await sendEth(sendInfo);
        console.log(`sendTransfer_ETH`,res)

        return res
    }catch (e) {
        return {success:false,falseReason:e.message}
    }
}
export const checkAddress_ETH = (address:string) => {
    try {
        ethers.utils.getAddress(address);
        return true
    }
    catch (e) {
        console.log(e)
        return false
    }
}
export const isContract_ETH = async (address: string) => {
    initProvider();
    return await provider.getCode(address)!=="0x"
}
export const getTransferList_ETH = async (address:string,chainID:string,tokenAddress?:string) => {
    let net = await getChainBaseByChainID(chainID);
    let url;
    if(!tokenAddress)
    {
        url = net?.blockNetApi+`?module=account&action=txlist&address=${address}&apikey=${net?.blockNetKey}`;
    }
    else
    {
        url = net?.blockNetApi+`?module=account&action=tokentx&address=${address}&contractaddress=${tokenAddress}&apikey=${net?.blockNetKey}`;
    }
    console.log(url)
    let response = await Net(url,"");
    if(typeof response === "string")
    {
        response = JSON.parse(response);
    }
    if(response.message==="OK") {
        let tranList = response.result;
        return tranList;
    }
    return []
}



export const testApi = async () => {
    initProvider();
    let res = await isContract_ETH(nowWallet.address);
    let res2 = await isContract_ETH("0x9f8b3da60f8750e7c278e65edc4442a8e5f276a1");
    console.log(res,nowWallet.address)
    console.log(res2,"0x9f8b3da60f8750e7c278e65edc4442a8e5f276a1")
}
